﻿using System;
using System.Collections;
using System.IO;
using System.Windows;
using System.Windows.Annotations;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows.Threading;
using System.Windows.Annotations.Storage;
using System.IO.Packaging;
using System.Windows.Xps.Packaging;
using System.Windows.Xps.Serialization;
using System.Net;
using Sinacor.Infra.UI.Controls.SmartClient;
using System.Windows.Media.Animation;

namespace Sinacor.Infra.UI.Controls.SmartClient
{
    public partial class SinacorFlowDocumentReader : FlowDocumentReader
    {
        #region Constantes

        /// <summary>
        /// Constante com tempo, em milisegundos, de uma animação para exibir / esconder o controle de zoom.
        /// Este é o tempo de uma animação completa (tempo necessário para percorrer HEIGHTCONTROLEZOOM pixels).
        /// Se o controle estiver sendo parcialmente exibido, o tempo necessário é calculado de acordo com 
        /// uma proporção, para que não exista diferença na velocidade da animação.
        /// </summary>
        private const int TEMPOANIMACAOZOOMMILISEG = 200;//1000;

        /// <summary>
        /// Altura do controle de zoom. Usada para calcular proporção do tempo de animação quando o controle de zoom 
        /// está sendo exibido parcialmente (isto acontece se ele estiver no meio de uma animação).
        /// </summary>
        private const int HEIGHTCONTROLEZOOM = -120;

        #endregion

        #region Variaveis para controles de zoom

        /// <summary>
        /// Estado atual do controle de zoom
        /// </summary>
        public SinacorWindow.ZoomAnimationState _zoomAnimationState = SinacorWindow.ZoomAnimationState.Closed;

        /// <summary>
        /// Timer para controlar tempo de espera até que o controle de zoom seja fechado quando estiver sem o mouse
        /// sobre ele ou sem o foco no campo para digitar zoom
        /// </summary>
        System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();

        /// <summary>
        /// Armazena storyboard para mostrar controle de zoom
        /// </summary>
        Storyboard storyDisplayZoom = null;

        /// <summary>
        /// Armazena storyboard para esconder controle de zoom
        /// </summary>
        Storyboard storyHideZoom = null;

        /// <summary>
        /// Indica se o controle de zoom deve permanecer exibido ou se pode ser escondido
        /// </summary>
        private bool _KeepZoomControlOpened = false;

        /// <summary>
        /// Indica o controle de zoom
        /// </summary>
        private SinacorZoom _zoom = null;

        #endregion

        #region Public Properties

        /// <summary>
        /// Returns the title of the current document. SdkViewer XAML has the title embedded in the Tag property
        /// </summary>
        public string DocumentTitle
        {
            get
            {
                return Tag as string;
            }
        }

        /// <summary>
        /// Returns the unique document title for each SDK document.
        /// </summary>
        public string DocumentID
        {
            get
            {
                return Name as string;
            }
        }

        #endregion 

        #region Constructors

        public SinacorFlowDocumentReader()
            : base()
        {
            this.Loaded += new RoutedEventHandler(SinacorFlowDocumentReader_Loaded);

            CommandBindings.Add(new CommandBinding(SinacorWindowCommands.ShowZoomControl, btnOpenZoom_Click));

            timer = new System.Windows.Threading.DispatcherTimer();
            timer.Interval = new TimeSpan(0, 0, 0, 3, 0);
            timer.IsEnabled = false;
            timer.Tick += new EventHandler(timer_Tick);
        }

        #endregion Constructors

        #region Loaded/Unloaded

        void SinacorFlowDocumentReader_Loaded(object sender, RoutedEventArgs e)
        {
            object objectDisplayZoom = null;
            object objectHideZoom = null;

            if (_zoom != null)
            {
                _zoom.MouseEnter += new MouseEventHandler(zoom_MouseEnter);
                _zoom.MouseLeave += new MouseEventHandler(zoom_MouseLeave);
                _zoom.LostFocusZoomText += new SinacorZoom.LostFocusZoomTextHandler(zoom_LostFocusZoomText);
                _zoom.GotFocusZoomText += new SinacorZoom.GotFocusZoomTextHandler(zoom_GotFocusZoomText);
            }

            objectDisplayZoom = this.TryFindResource("AnimationDisplayMenu");
            if (objectDisplayZoom != null)
            {
                storyDisplayZoom = ((Storyboard)this.FindResource("AnimationDisplayMenu")).Clone();
                storyDisplayZoom.Completed += new EventHandler(storyDisplayZoom_Completed);
            }

            objectHideZoom = this.TryFindResource("AnimationHideMenu");
            if (objectHideZoom != null)
            {
                storyHideZoom = ((Storyboard)this.FindResource("AnimationHideMenu")).Clone();
                storyHideZoom.Completed += new EventHandler(storyHideZoom_Completed);
            }
        }

        #endregion

        #region Métodos

        private Decorator _contentHost;

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this._contentHost = base.GetTemplateChild("PART_ContentHost") as Decorator;

            this._zoom = base.GetTemplateChild("PART_Zoom") as SinacorZoom;
        }

        #endregion

        #region Métodos para controle de zoom

        //<summary>
        //Método para executar animação do controle de zoom, seja ela para apresentar ou esconder o controle
        //</summary>
        public void AnimateZoom()
        {
            Storyboard story = null;
            if (_zoom != null)
            {
                switch (this._zoomAnimationState)
                {
                    case SinacorWindow.ZoomAnimationState.Closed:
                        story = this.storyDisplayZoom;
                        this._zoomAnimationState = SinacorWindow.ZoomAnimationState.Opening;
                        break;
                    case SinacorWindow.ZoomAnimationState.Closing:
                        story = this.storyDisplayZoom;
                        this._zoomAnimationState = SinacorWindow.ZoomAnimationState.Opening;
                        break;
                    case SinacorWindow.ZoomAnimationState.Opened:
                        story = this.storyHideZoom;
                        this._zoomAnimationState = SinacorWindow.ZoomAnimationState.Closing;
                        break;
                    case SinacorWindow.ZoomAnimationState.Opening:
                        story = this.storyHideZoom;
                        this._zoomAnimationState = SinacorWindow.ZoomAnimationState.Closing;
                        break;
                    default:
                        break;
                }
                if (story != null)
                {
                    DependencyObject btnZoom = this.GetTemplateChild("PART_ButtonZoom");
                    story.Begin((FrameworkElement)btnZoom);
                }
            }
        }

        #endregion

        #region Eventos usados no controle de zoom

        /// <summary>
        /// MouseLeave do controle de zoom, deve indicar que controle pode ser fechado (se não estiver com o foco no campo para digitar o zoom)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void zoom_MouseLeave(object sender, MouseEventArgs e)
        {
            bool executa = true;

            if (_zoom != null)
            {
                executa = !_zoom.IsZoomTextFocused;
            }
            if (executa)
            {
                this._KeepZoomControlOpened = false;
                timer.IsEnabled = true;
            }
        }

        /// <summary>
        /// MouseEnter do controle de zoom, deve indicar que o controle precisa permanecer sendo exibido
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void zoom_MouseEnter(object sender, MouseEventArgs e)
        {
            this._KeepZoomControlOpened = true;
            timer.IsEnabled = false;
            if (this._zoomAnimationState == SinacorWindow.ZoomAnimationState.Closing)
            {
                AnimateZoom();
            }
        }

        /// <summary>
        /// Evento disparado no timer para esconder controle de zoom
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void timer_Tick(object sender, EventArgs e)
        {
            if (!this._KeepZoomControlOpened && this._zoomAnimationState == SinacorWindow.ZoomAnimationState.Opened)
            {
                timer.IsEnabled = false;
                AnimateZoom();
            }
        }

        /// <summary>
        /// Evento para quando o controle de zoom ganha foco no text para digitação do zoom
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void zoom_GotFocusZoomText(object sender, RoutedEventArgs e)
        {
            this._KeepZoomControlOpened = true;
            timer.IsEnabled = false;
            if (this._zoomAnimationState == SinacorWindow.ZoomAnimationState.Closing)
            {
                AnimateZoom();
            }
        }

        /// <summary>
        /// Evento para quando o controle de zoom perde foco no text para digitação do zoom
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void zoom_LostFocusZoomText(object sender, RoutedEventArgs e)
        {
            bool executa = true;

            if (_zoom != null)
            {
                executa = !_zoom.IsMouseOver;
            }
            if (executa)
            {
                this._KeepZoomControlOpened = false;
                timer.IsEnabled = true;
            }
        }

        /// <summary>
        /// Evento indicando fim de animação para mostrar controle de zoom
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void storyDisplayZoom_Completed(object sender, EventArgs e)
        {
            if (this._zoomAnimationState == SinacorWindow.ZoomAnimationState.Opening)
                this._zoomAnimationState = SinacorWindow.ZoomAnimationState.Opened;
        }

        /// <summary>
        /// Evento indicando fim de animação para esconder controle de zoom
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void storyHideZoom_Completed(object sender, EventArgs e)
        {
            if (this._zoomAnimationState == SinacorWindow.ZoomAnimationState.Closing)
                this._zoomAnimationState = SinacorWindow.ZoomAnimationState.Closed;
        }

        /// <summary>
        /// Evento de click do botão para exibir/esconder o controlde de zoom
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnOpenZoom_Click(object sender, EventArgs e)
        {
            AnimateZoom();
            // Como ao clicar no botão o mouse sempre estará fora do SinacorZoom, os 3 segundos para fechar ficam valendo 
            // (se o usuário só clicar no botão mas não colocar o mouse dentro do SinacorZoom, o controle fecha após 3 segundos)
            this._KeepZoomControlOpened = false;
            // Ativa o timer
            timer.IsEnabled = true;
        }

        #endregion
    }
}